import java.io.*;
import java.util.*;

public class SorterPostThread extends Thread {

	/*~~~~ ATTRIBUTES ~~~~*/

	protected boolean blnLinearSorting = false; 
	protected EventsManager objEventManager;
	protected Vector<Event> objEvents;
	protected String outputFileName = null;
	protected String inputFileHTML = null;
	protected String outputFileHTML = null;


	/*~~~~ CONSTRUCTORS ~~~~*/

	public SorterPostThread(EventsManager objEventManager) {
		objEvents = new Vector<Event>();
		this.objEventManager = objEventManager;
	}

	/*~~~~ RUN ~~~~*/
	public void run() {
		try {
			Event objEvent;
			/* While I read valid strings */
			while ((objEvent = objEventManager.getObjEventValue()) != null) {
				/*Safe*/ if (objEvents == null) objEvents = new Vector<Event>();
				int intIndex = 0;

				if (objEvent != null) {
					if (blnLinearSorting)
						insertEvent(objEvent);
					else {
						intIndex = getSortingSuggestion(objEvents, objEvent.getGcalWhen().getTimeInMillis());
						if (intIndex > -1) objEvents.add(intIndex, objEvent.clone());
						//else return objEvents; 
						//-1 means an error in getSortingSuggestion() method
					}
				}
			}
			/* Go make HTML file */
			if (outputFileHTML != null) {
				HTMLThread objHTMLThread = new HTMLThread(objEvents, inputFileHTML, outputFileHTML);
				objHTMLThread.start();
			}
			/* Go make report file */
			makeReportFile();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}		
	}


/*~~~~ PUBLIC METHODS ~~~~*/

	public void setDoReport(String outputFileName) {
		this.outputFileName = outputFileName;
	}


	public void setDoHTML(String inputFileHTML, String outputFileHTML) {
		this.inputFileHTML = inputFileHTML;
		this.outputFileHTML = outputFileHTML;
	}


	public void makeReportFile(String outputFileName) {
		try {
			if (outputFileName != null) {
				/**/System.out.println("Now writing data on \"" + outputFileName + "\"...");/**/
				for (int i = 0; i < objEvents.size(); i++) {
					if (i == 0)
						objEvents.get(i).saveOnFile(outputFileName); // First call overwrite file and makes new
					else
						objEvents.get(i).saveOnFile(outputFileName, true); // Other calls appends output on such file
				}
			}
			/**/System.out.println("Data wrote on \"" + outputFileName + "\"...");/**/
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	public void makeReportFile() {
		makeReportFile(outputFileName);
	}


	private void insertEvent(Event objEvent)
	{
		if(objEvents.size() == 0)
		{
			objEvents.add(objEvent);
		}
		else
		{
			boolean blnIns = false;
			for(int i = 0; i < objEvents.size(); i++)
			{
				if(compareDate(objEvent, objEvents.get(i)) == true)
				{
					continue;
				} else {
					objEvents.add(i, objEvent);
					blnIns = true;
					break;
				}
			}
			if(blnIns == false) objEvents.add(objEvent);
		}
	}


	public boolean compareDate(Event objEvent1, Event objEvent2)
	{
		Calendar objDate1 = objEvent1.getGcalWhen();
		Calendar objDate2 = objEvent2.getGcalWhen();
		return objDate1.after(objDate2);
	}


	public int getSortingSuggestion(Vector<Event> objEvents, long lngCompare){
		if (objEvents.size() > 0) {
			int intMin = 0, intMax = objEvents.size() /*-1*/, intNow = objEvents.size()/2;
			long lngNowDate = objEvents.get(intNow).getGcalWhen().getTimeInMillis();
			long lngNextDate;
			if (intNow + 1 < intMax)
				lngNextDate = objEvents.get(intNow + 1).getGcalWhen().getTimeInMillis();
			else
				lngNextDate = objEvents.get(objEvents.size()- 1).getGcalWhen().getTimeInMillis() + 1;

			do {
				/*Safe*/ if (lngNowDate > lngNextDate) {
					/*Safe*/ System.out.println("Infinite cycle check fault.");
					/*Safe*/ return -1;
				} else if (lngCompare < lngNowDate && lngCompare < lngNextDate) {
					intMax = intNow;
				} else if (lngCompare > lngNowDate && lngCompare > lngNextDate) {
					intMin = intNow + 1;
				} else if (lngCompare >= lngNowDate && lngCompare < lngNextDate) {
					return intNow + 1;
				} else if (lngCompare == lngNextDate) {
					intMin = intNow + 1;
					intMax = intNow + 2;
				}
				/*Safe*/ if (intMax > objEvents.size()) intMax = objEvents.size();
				/*Safe*/ if (intMin < 0) intMax = 0;
				if (intMin == intMax || (intMin == objEvents.size() - 1 && intMax == objEvents.size()))
					return intMax;
				/*Safe*/ if (intMin == objEvents.size()) return intMin;
				/*Safe*/ if (intMax == 0) return 0;
				intNow = intMin + ((intMax - intMin) / 2);
				lngNowDate = objEvents.get(intNow).getGcalWhen().getTimeInMillis();
				if (intNow + 1 < objEvents.size())
					lngNextDate = objEvents.get(intNow + 1).getGcalWhen().getTimeInMillis();
				else
					lngNextDate = objEvents.get(objEvents.size()- 1).getGcalWhen().getTimeInMillis() + 1;
			} while (true);
		}
		return 0;
	}


/*~~~~ GET METHODS ~~~~*/

	public boolean isBlnLinearSorting() {
		return blnLinearSorting;
	}


/*~~~~ SET METHODS ~~~~*/

	public void setBlnLinearSorting(boolean blnLinearSorting) {
		this.blnLinearSorting = blnLinearSorting;
	}
}
